<?php namespace App\Repositories;

use App\Presenters\CommonPresenter;
use App\Services\Helper;
use App\Services\Tree;
use Illuminate\Support\Facades\DB;

abstract class BaseRepository {

	/**
	 * The Model instance.
	 *
	 * @var Illuminate\Database\Eloquent\Model
	 */
	protected $model;

	/**
	 * 获取主model条数.
	 *
	 * @return array
	 */
	public function getNumber()
	{
		$total = $this->model->count();


		return compact('total');
	}

    /**
     * 获取所用model的表名
     * @return mixed
     */
	public function getTable()
    {
        return $this->model->getTable();
    }

    /**
     *获取当前model的表结构
     */
    public function getTableStruct()
    {
        $table = $this->getTable();
        $tableObj = DB::select("SHOW FULL COLUMNS FROM ".$table);
        $tableInfo = array_map('get_object_vars', $tableObj);
        return $tableInfo;
    }

	/**
	 * Destroy a model.
	 *
	 * @param  int $id
	 * @return void
	 */
	public function destroy($id)
	{
		$this->getById($id)->delete();
	}

    /**
     * 删除(软删除)
     * @param $id
     * @return bool
     */
    public function delete($id)
    {

        $model = $this->model->find($id);
        $model->delete();
        if($model->trashed()){
            return true;
        }else{
            return false;
        }
    }

	/**
	 * Get Model by id.
	 *
	 * @param  int  $id
	 * @return App\Models\Model
	 */
	public function getById($id)
	{
        return $this->model->find($id);
	}

    /**
     * 生成密码
     * @param $pwd 明文密码
     * @param string $salt 密码盐值
     * @return string
     */
	public function setPassword($pwd, $salt = '')
    {
        return md5($pwd.$salt);
    }

    /**
     * 尽可能多的解析搜索条件
     * @param null $where
     * @return mixed
     */
    protected function parseWhere($where=null)
    {
        if(empty($where)) {
            return [];
        }

        if(is_array($where)) {
            unset($where['limit']);
            unset($where['page']);
            foreach ($where as $k=>$v) {

                if(empty($v)&&$v!==0) {
                    unset($where[$k]);
                }
            }
            return $where;
        }
        return $where;
    }

    /**
     * 根据条件获取结果集
     * @param $where 条件
     * @return array
     */
    public function getRow($where,$field=[])
    {
        $where = $this->parseWhere($where);
        if (empty($field))
            return $this->model->where($where)->first();
        else
            return $this->model->where($where)->first($field);
    }

    /**
     * 条件和排序获得结果集
     * @param $where 条件
     * @param $orderby 排序
     * @param array $field
     */
    public function getOrderByRow($where,$orderby,$field=[])
    {
        $where = $this->parseWhere($where);
        $model =  $this->model->where($where);
        $model = $model->orderByRaw($orderby);
        if (empty($field))
            return $model->where($where)->first();
        else
            return $model->where($where)->first($field);
    }

    /**
     * 获取后台所需列表数据，带分页
     * @param null $where
     * @param null $order
     * @return mixed
     */
    public function getTableList($where=null, $order=null)
    {
        $limit = isset($where['limit']) ? $where['limit']:config('common.default_page_limit');  //这个10取配置里的
        $where = $this->parseWhere($where);

        //order 必须以 'id desc'这种方式传入.

        $query = $this->model;
        //创建时间查询
        if(isset($where['created_at']) && !empty($where['created_at'])){
            $created_at = $where['created_at'];
            $time_list = Helper::getTimeRangedata($created_at);
            $query = $query->whereBetween("created_at",[$time_list['start'],$time_list['end']]);
            unset($where['created_at']);
        }

        if(!empty ($where)) {
            $query =  $query->where($where);
        }
        if(!empty($order)) {
            $arrOrder = explode(' ', $order);
            $t = count($arrOrder) / 2;
            for ($i = 0 ; $i< $t; $i++) {
                $query =  $query->orderBy($arrOrder[2*$i],$arrOrder[2*$i+1]);
            }
        }

        $list = $query->paginate($limit);
        return $list;
    }
    /**
     * 根据条件获取结果集
     * @param $where
     * @param string $order
     * @param string $sort
     * @return mixed
     */
    public function getList($where,$order='id asc')
    {
        $where = $this->parseWhere($where);
        $orderBy = [];
        if (!empty ($order)) {
            $arrOrder = explode(' ', $order);
            if(count($arrOrder) == 2) {
                $orderBy = $arrOrder;
            }
        }

        $query = $this->model;
        //创建时间查询
        if(isset($where['created_at']) && !empty($where['created_at'])){
            $created_at = $where['created_at'];
            $time_list = Helper::getTimeRangedata($created_at);
            $query = $query->whereBetween("created_at",[$time_list['start'],$time_list['end']]);
            unset($where['created_at']);
        }

        if(!empty ($where)) {
            $query =  $query->where($where);
        }
        if(!empty($order)) {
            $query =  $query->orderBy($orderBy[0],$orderBy[1]);
        }

        $list = $query->get();
        return $list;
    }

    /**
     * 装数据库的标识、状态、类型转换为实际值，在具体仓库
     * 中实现
     * @param $data
     * @return mixed
     */
    public function transFlagToEntity($data)
    {
        $adminInfo = app(PrtAdminRepository::class)->getRows([],'id')->toArray();
        $adminKv = array_column($adminInfo,'username','id');

        if (!empty($data)) {
            $commonPresenter = app(CommonPresenter::class);
            if (isset($data[0]) && is_array($data[0])) { //列表list处理
                foreach ($data as $k=>$v) {
                    //$data[$k]['status'] = $commonPresenter->getEnabledOrDisabled($v['status']); //转化状态
                    $data[$k]['created_at'] = $commonPresenter->exchangeTime($v['created_at']); //转化状态
                    $data[$k]['updated_at'] = $commonPresenter->exchangeTime($v['updated_at']); //转化状态
                }
            } else { //单条信息处理
               // $data['status'] = $commonPresenter->getEnabledOrDisabled($data['status']); //转化状态
                $data['created_at'] = $commonPresenter->exchangeTime($data['created_at']); //转化状态
                $data['updated_at'] = $commonPresenter->exchangeTime($data['updated_at']); //转化状态
            }
        }

        return $data;
    }
    /**
     * 反向转化实体为标识。自行实现
     * @param $data
     * @return mixed
     */
    public function unTransFlagToEntity($data)
    {
        return $data;
    }

    /**
     * 获取结果集,比getList更灵活
     * @param $where
     * @param string $order
     * @param string $sort
     * @param int $limit
     */
    public function getRows($where, $order="id",$sort="desc", $limit = 0)
    {
        $query = $this->model;
        foreach ($where as $k=>$v) {
            if (is_array($v)) {
                $query = $query->whereIn($k,$v);
            } else {
                $query = $query->where($k,$v);
            }
        }

        $query = $query->orderby($order,$sort);
        if (!empty($limit)) {
            $query = $query->limit($limit);
        }

        return $query->get();
    }

    /**
     * 获取指定值的列表
     * @param $where
     * @param array $field
     * @return mixed
     */
    public function getValues($where, $field = [])
    {
        $query = $this->model;
        foreach ($where as $k=>$v) {
            if (is_array($v)) {
                $query = $query->whereIn($k,$v);
            } else {
                $query = $query->where($k,$v);
            }
        }

        if (!empty($limit)) {
            $query = $query->limit($limit);
        }

        return $query->get($field);
    }

    /**
     * @param $where  条件
     * @param int $offset 偏移量
     * @param int $limit  每页多少个
     * @param $order  排序
     * @param string $sort
     * @return array
     */
    public function getRowsPage($where, $offset, $limit , $order, $sort="desc")
    {
        $query = $this->model;
        foreach ($where as $k=>$v) {
            if (is_array($v)) {
                $query = $query->whereIn($k,$v);
            } else {
                $query = $query->where($k,$v);
            }
        }
        $count = $query->count();
        $list = $query->offset($offset)->limit($limit)->orderby($order,$sort)->get()->toArray();

        return [
            'list'    => $list,
            'count'   => $count
        ];
    }

    /**
     * 插入记录
     * @param $data
     * @return int|boolean
     */
    public function insert($data)
    {
        $ret = $this->model->create($data);
        return $ret;
    }
    /**
     * 获取插入id
     * @param $data
     * @return int|boolean
     */
    public function insertGetId($data)
    {
        $ret = $this->model->insertGetId($data);
        return $ret;
    }

    /**
     * 更新记录
     * @param $where
     * @param $data
     */
    public function update($where, $data)
    {
        return $this->model->where($where)->update($data);
    }

    /**
     * 支持whereIn的更新
     * @param $where
     */
    public function updateWhere($where,$data)
    {
        $query = $this->model;
        foreach ($where as $k=>$v) {
            if (is_array($v)) {
                $query = $query->whereIn($k,$v);
            } else {
                $query = $query->where($k,$v);
            }
        }
        $query->update($data);
    }

    /**
     * whereIn查询
     * @param $field
     * @param $array
     */
    public function WhereIn($field, $array)
    {
        return $this->model->WhereIn($field,$array)->get();
    }

    /**
     *获取仓库对应的model
     */
    public function getModel()
    {
        return $this->model;
    }
    /**
     *获取缓存数据
     */
    public function getByIdFromCache($id)
    {

        if (isset($this->isCache)&&$this->isCache === true){
            //查询缓存直接返回缓存数据
            $table_name = $this->model->getTable();
            $redis = app('redis.connection');

            $data = json_decode($redis->get($table_name.'_'.$id),true);
            if (empty($data)){
                //缓存找不到则查询数据库
                return $this->model->find($id)?$this->model->find($id)->toArray():null;
            }
            return $data;
        }else{
            return $this->model->find($id)?$this->model->find($id)->toArray():null;
        }
    }

    /**
     * 新增/修改
     * @param $data
     * @return boolean
     */
    public function save($data)
    {
        if(empty($data['id'])) {
            unset($data['id']);
            $ret = $this->model->insertGetId($data);
            $priKeyValue = $ret;
        } else {
            $priKeyValue = $data['id'];
            unset($data['id']);
            $ret =$this->model->where('id',$priKeyValue)->update($data);
        }
        return $ret;
    }

    /**
     * 批量更新数据
     * @param $data
     * @return boolean
     */
    public function batchUpdate($tableName, $data)
    {
        foreach ($data as $k => $row) {
            $set_arr = array();
            $arr_key = array();
            $fields = array();

            foreach ($row as $key=>$val){

                if($key != $this->model->getKeyName()){
                    $fields[] = $key.'=VALUES('.$key.')';
                }
                $arr_key[] = $key;
                $set_arr[] = '\''.addslashes($val).'\'';
            }

            $arr_value[] = '('.implode(',',$set_arr).')';
        }
        if(!empty($set_arr)){
            $sql = 'INSERT INTO '.$tableName . ' ('.implode(',',$arr_key).') VALUES ' . implode(', ', $arr_value) . ' ON DUPLICATE KEY UPDATE '.implode(',',$fields);
            $ret = \DB::getPdo()->exec($sql);
            if(!empty($ret) || $ret === 0){
                return true;
            }else{
                Helper::EasyThrowException('10020',__FILE__.__LINE__);
            }
        }

        return true;
    }
    /**
     * 批量更新数据
     * @param $data
     * @return boolean
     */
    public function batchInsert($tableName ='', $data)
    {
        if (empty($tableName)) {
            $tableName = $this->getTable();
        }
        foreach($data as $k=>$row){
            $set_arr = array();
            $arr_key = array();
            $fields = array();

            foreach ($row as $key=>$val){

                if($key != $this->model->getKeyName()){
                    $fields[] = $key.'=VALUES('.$key.')';
                }
                $arr_key[] = $key;
                $set_arr[] = '\''.addslashes($val).'\'';
            }

            $arr_value[] = '('.implode(',',$set_arr).')';
        }
        if(!empty($set_arr)){
            $sql = 'INSERT INTO '.$tableName . ' ('.implode(',',$arr_key).') VALUES ' . implode(', ', $arr_value);
            $ret = \DB::getPdo()->exec($sql);
            if(!empty($ret) || $ret === 0){
                return true;
            }else{
                Helper::EasyThrowException('10020',__FILE__.__LINE__);
            }
        }

        return true;
    }

    /**
     * @desc arraySort php二维数组排序 按照指定的key 对数组进行自然排序
     * @param array $arr 将要排序的数组
     * @param string $keys 指定排序的key
     * @param string $type 排序类型 asc | desc
     * @return array
     */
    public function arraySort($arr, $keys, $type = 'asc')
    {
        $keysvalue = $new_array = array();
        foreach ($arr as $k => $v) {
            $keysvalue[$k] = $v[$keys];
        }
        // dump($keysvalue);

        if ($type == 'asc') {
            natcasesort($keysvalue);
        }
        if ($type == 'desc') {
            natcasesort($keysvalue);
            $keysvalue = array_reverse($keysvalue, TRUE);
        }
        // dump($keysvalue);
        foreach ($keysvalue as $k => $v) {
            $new_array[$k] = $arr[$k];
        }
        // dump($new_array);
        return $new_array;

    }

    /**
     * 字段自增
     * @param $field
     * @param int $num
     */
    public function increment($where,$field,$num=1)
    {
        $this->model->where($where)->increment($field,$num);
    }

    /**
     * 获取字段值
     * @param $field
     * @param int $num
     */
    public function getValue($where,$field)
    {
       $value = $this->model->where($where)->value($field);
       return $value;
    }

    /**
     * 获取某个字段的数组
     * @param $field
     * @param int $num
     */
    public function getPluck($where,$field)
    {
        $array = $this->model->where($where)->pluck($field)->toArray();
        return $array;
    }

    //判断符合条件的数据是否存在
    public function isExists($where)
    {
        $exist = $this->model->where($where)->exists();
        return $exist;
    }

    /**
     * @param $where 条件中可以包含limit和page
     * @param $order "id desc"
     */
    public function getApiList($where , $order = '')
    {
        $limit = $where['limit'] ?? 0;
        $page  = $where['page']  ?? 1;

        $where = $this->parseWhere($where);

        //order 必须以 'id desc'这种方式传入.
        $orderBy = [];
        if (!empty ($order)) {
            $arrOrder = explode(' ', $order);
            if(count($arrOrder) == 2) {
                $orderBy = $arrOrder;
            }
        }

        $query = $this->model;
        //创建时间查询
        if(isset($where['created_at']) && !empty($where['created_at'])){
            $created_at = $where['created_at'];
            $time_list = Helper::getTimeRangedata($created_at);
            $query = $query->whereBetween("created_at",[$time_list['start'],$time_list['end']]);
            unset($where['created_at']);
        }
        //更新时间查询
        if(isset($where['updated_at']) && !empty($where['updated_at'])){
            $updated_at = $where['updated_at'];
            $time_list = Helper::getTimeRangedata($updated_at);
            $query = $query->whereBetween("updated_at",[$time_list['start'],$time_list['end']]);
            unset($where['updated_at']);
        }

        if(!empty ($where)) {
            $query =  $query->where($where);
        }
        //可以多个，比如 "id desc create_ad asc"
        if(!empty($order)) {
            $t = count($arrOrder) / 2;
            for ($i = 0 ; $i< $t; $i++) {
                $query =  $query->orderBy($orderBy[2*$i],$orderBy[2*$i+1]);
            }
        }

        if (!empty($limit)) {
            $query = $query->offset(($page-1)*$limit)->limit($limit);
        }

        $list = $query->get()->toArray();
        return $list;
    }

    /**
     * 获取记录总数
     * @param $where
     * @return int
     */
    public function getCount($where,$groupBy = [])
    {
        //$count = $this->model->where($where)->count();
        $query = $this->model->where($where);
        if (!empty($groupBy)) {
            $query = $query->groupBy($groupBy)->get($groupBy);
        }

        return $query->count();
    }

    /**
     * 分组
     * @param array $fileds
     */
    public function groupBy($where,$fileds = [])
    {
        $model = $this->model->where($where)->groupBy($fileds);
        return $model;
    }

    /**针对原生sql获取的列表里对象转数组
     * @param $array
     * @return array
     */
    public function  objectArray($array)
    {
        if(is_object($array)) {
            $array = (array)$array;
        } if(is_array($array)) {
            foreach($array as $key=>$value) {
                $array[$key] = $this->objectArray($value);
            }
        }
        return $array;
    }

    /**
     * 获取列表树形结构
     * @param $list 表记录
     * @param $pid  父id
     * @param $id   表id
     * @param $name 名称
     * @return array
     */
    public function getTreeList($list,$pid,$id,$name)
    {
        $tree = new Tree();

        $tree::instance()->init($list,$pid,$id);

        $treeList = $tree::instance()->getTreeList($tree::instance()->getTreeArray(0), $name);
        return $treeList;
    }
}
